using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace WaveLib
{
    public partial class SoundUserControl : UserControl
    {
        public event EventHandler SoundRecordedEvent;

        public SoundUserControl()
        {
            InitializeComponent();
            playButton.Enabled = false;
        }

        private WaveLib.WaveOutPlayer m_Player;
        private WaveLib.WaveInRecorder m_Recorder;
        private System.IO.MemoryStream mstr = new System.IO.MemoryStream(16384 * 3);

        private byte[] m_PlayBuffer;
        private byte[] m_RecBuffer;

        //WaveLib.WaveFormat fmt = new WaveLib.WaveFormat(44100, 16, 2);

        public bool ShowRecordButton
        {
            get { return recButton.Visible; }
            set { recButton.Visible = value; }
        }

        public bool ShowStopButton
        {
            get { return stopButton.Visible; }
            set { stopButton.Visible = value; }
        }

        public bool ShowProgress
        {
            get { return soundProgressBar.Visible; }
            set { soundProgressBar.Visible = value; }
        }

        public byte[] SoundSample
        {
            get
            {
                return mstr.ToArray();
            }
            set
            {
                mstr.SetLength(0);

                if (value != null)
                {
                    mstr.Write(value, 0, value.Length);
                }
            }
        }

        private void Filler(IntPtr data, int size)
        {
            if (m_PlayBuffer == null || m_PlayBuffer.Length < size)
                m_PlayBuffer = new byte[size];

            if ((mstr.Length - mstr.Position) >= size)
                mstr.Read(m_PlayBuffer, 0, size);
            else
                for (int i = 0; i < m_PlayBuffer.Length; i++)
                   m_PlayBuffer[i] = 0;

            this.ParentForm.BeginInvoke(new InvokeDelegateP(UpdatePositionLabel), mstr.Position, mstr.Length);
            //UpdatePositionLabel(mstr.Position, mstr.Length);
            System.Runtime.InteropServices.Marshal.Copy(m_PlayBuffer, 0, data, size);
        }

        private void DataArrived(IntPtr data, int size)
        {
            if (m_RecBuffer == null || m_RecBuffer.Length < size)
                m_RecBuffer = new byte[size];

            System.Runtime.InteropServices.Marshal.Copy(data, m_RecBuffer, 0, size);

            mstr.Write(m_RecBuffer, 0, m_RecBuffer.Length);
            
            bufferSizeLabel.BeginInvoke( new InvokeDelegate(UpdateSizeLabel));
            //UpdateSizeLabel();
            
        }

        private void UpdateSizeLabel()
        {
            bufferSizeLabel.Text = string.Format("{0} bytes", mstr.Length);
        }

        private void UpdatePositionLabel( long pos, long len)
        {
            if (len == 0) return;

            soundProgressBar.Value = (int)(pos * 1.0 / len * 100.0);
            playPositionLabel.Text = string.Format("Position: {0}", pos);

            if (pos == len) StopPlay();
        }

        public void StopRecording()
        {
            if (m_Recorder != null)
                try
                {
                    m_Recorder.Dispose();

                    if (SoundRecordedEvent != null) SoundRecordedEvent(this, null);
                }
                finally
                {
                    m_Recorder = null;
                }

            bufferSizeLabel.Text = string.Format("{0} bytes", mstr.Length);
        }

        public void StopPlay()
        {
            if (m_Player != null)
                try
                {
                    m_Player.Dispose();
                }
                finally
                {
                    m_Player = null;
                }

            playButton.Enabled = true;
        }

        public void Record()
        {
            StopRecording();
            mstr.SetLength(0); // clear all pending data
            bufferSizeLabel.Text = string.Format("{0} bytes", mstr.Length);

            try
            {
                WaveLib.WaveFormat fmt = new WaveLib.WaveFormat(44100, 16, 2);
                m_Recorder = new WaveLib.WaveInRecorder(-1, fmt, 16384, 3, new WaveLib.BufferDoneEventHandler(DataArrived));
            }
            catch
            {
                StopRecording();
                throw;
            }
        }

        public void Play()
        {
            if (mstr.Length == 0)
            {
                playButton.Enabled = false;
                return;
            }

            StopRecording();
            StopPlay();
            mstr.Position = 0;
            soundProgressBar.Value = 0;

            playButton.Enabled = false;

            try
            {
                WaveLib.WaveFormat fmt = new WaveLib.WaveFormat(44100, 16, 2);
                m_Player = new WaveLib.WaveOutPlayer(-1, fmt, 16384, 3, new WaveLib.BufferFillEventHandler(Filler));
            }
            catch
            {
                StopPlay();
                throw;
            }
        }

        private void recButton_Click(object sender, EventArgs e)
        {
            Record();
        }

        private void stopButton_Click(object sender, EventArgs e)
        {
            if (m_Player != null) StopPlay();
            else if (m_Recorder != null)
            {
                StopRecording();
                if (mstr.Length > 0) playButton.Enabled = true;
            }
        }

        private void playButton_Click(object sender, EventArgs e)
        {
            Play();
        }

    }

    public delegate void InvokeDelegate();
    public delegate void InvokeDelegateP(long pos, long len);

}
